package query

import (
	"time"

	"github.com/pingcap/errors"
	depquery "github.com/romberli/das/internal/dependency/query"
	"github.com/romberli/go-util/constant"
	"github.com/romberli/go-util/middleware/sql/parser"
)

const (
	GetByMySQLServerAndMonitorSystemInfoPath          = "/api/v1/query/server-monitor"
	GetByDBNameAndMySQLServerAndMonitorSystemInfoPath = "/api/v1/query/db-server-monitor"
	GetBySQLIDAndMySQLServerAndMonitorSystemInfoPath  = "/api/v1/query/sql-server-monitor"

	MySQLServerAndMonitorSystemInfoHTTPBodyTemplate          = `{"mysql_server_host_ip": "%s", "mysql_server_port_num": %d, "mysql_server_service_name": "%s", "monitor_system_system_type": %d, "monitor_system_host_ip": "%s", "monitor_system_port_num_slow": %d, "start_time": "%s", "end_time": "%s", "limit": %d, "offset": %d, "login_name": "%s" }`
	DBNameAndMySQLServerAndMonitorSystemInfoHTTPBodyTemplate = `{"db_name": "%s", "mysql_server_host_ip": "%s", "mysql_server_port_num": %d, "mysql_server_service_name": "%s", "monitor_system_system_type": %d, "monitor_system_host_ip": "%s", "monitor_system_port_num_slow": %d, "start_time": "%s", "end_time": "%s", "limit": %d, "offset": %d, "login_name": "%s" }`
	SQLIDAndMySQLServerAndMonitorSystemInfoHTTPBodyTemplate  = `{"sql_id": "%s", "mysql_server_host_ip": "%s", "mysql_server_port_num": %d, "mysql_server_service_name": "%s", "monitor_system_system_type": %d, "monitor_system_host_ip": "%s", "monitor_system_port_num_slow": %d, "start_time": "%s", "end_time": "%s", "limit": %d, "offset": %d, "login_name": "%s" }`
)

type MySQLClusterRange struct {
	Token          string `json:"token" binding:"required"`
	MySQLClusterID int    `json:"mysql_cluster_id" bind:"required"`
	StartTime      string `json:"start_time" bind:"required"`
	EndTime        string `json:"end_time" bind:"required"`
	Limit          int    `json:"limit" bind:"required"`
	Offset         int    `json:"offset" bind:"required"`
	LoginName      string `json:"login_name" bind:"required"`
}

// GetToken returns the token
func (mcr *MySQLClusterRange) GetToken() string {
	return mcr.Token
}

// GetMySQLClusterID() returns the mysql cluster id
func (mcr *MySQLClusterRange) GetMySQLClusterID() int {
	return mcr.MySQLClusterID
}

// GetStartTime returns the start time
func (mcr *MySQLClusterRange) GetStartTime() string {
	return mcr.StartTime
}

// GetEndTime returns the end time
func (mcr *MySQLClusterRange) GetEndTime() string {
	return mcr.EndTime
}

// GetLimit returns the limit
func (mcr *MySQLClusterRange) GetLimit() int {
	return mcr.Limit
}

// GetOffset returns the offset
func (mcr *MySQLClusterRange) GetOffset() int {
	return mcr.Offset
}

// GetLoginName returns the login name
func (mcr *MySQLClusterRange) GetLoginName() string {
	return mcr.LoginName
}

// GetConfig gets the configuration
func (mcr *MySQLClusterRange) GetConfig() (depquery.Config, error) {
	return getConfig(mcr.GetStartTime(), mcr.GetEndTime(), mcr.GetLimit(), mcr.GetOffset(), mcr.GetLoginName())
}

type MySQLServerRange struct {
	Token         string `json:"token" binding:"required"`
	MySQLServerID int    `json:"mysql_server_id" bind:"required"`
	StartTime     string `json:"start_time" bind:"required"`
	EndTime       string `json:"end_time" bind:"required"`
	Limit         int    `json:"limit" bind:"required"`
	Offset        int    `json:"offset" bind:"required"`
	LoginName     string `json:"login_name" bind:"required"`
}

// GetToken returns the token
func (msr *MySQLServerRange) GetToken() string {
	return msr.Token
}

// GetMySQLServerID returns the mysql server id
func (msr *MySQLServerRange) GetMySQLServerID() int {
	return msr.MySQLServerID
}

// GetStartTime returns the start time
func (msr *MySQLServerRange) GetStartTime() string {
	return msr.StartTime
}

// GetEndTime returns the end time
func (msr *MySQLServerRange) GetEndTime() string {
	return msr.EndTime
}

// GetLimit returns the limit
func (msr *MySQLServerRange) GetLimit() int {
	return msr.Limit
}

// GetOffset returns the offset
func (msr *MySQLServerRange) GetOffset() int {
	return msr.Offset
}

// GetLoginName returns the login name
func (msr *MySQLServerRange) GetLoginName() string {
	return msr.LoginName
}

// GetConfig gets the configuration
func (msr *MySQLServerRange) GetConfig() (depquery.Config, error) {
	return getConfig(msr.GetStartTime(), msr.GetEndTime(), msr.GetLimit(), msr.GetOffset(), msr.GetLoginName())
}

type HostInfoRange struct {
	Token     string `json:"token" binding:"required"`
	HostIP    string `json:"host_ip" bind:"required"`
	PortNum   int    `json:"port_num" bind:"required"`
	StartTime string `json:"start_time" bind:"required"`
	EndTime   string `json:"end_time" bind:"required"`
	Limit     int    `json:"limit" bind:"required"`
	Offset    int    `json:"offset" bind:"required"`
	LoginName string `json:"login_name" bind:"required"`
}

// GetToken returns the token
func (hir *HostInfoRange) GetToken() string {
	return hir.Token
}

// GetHostIP returns the host ip
func (hir *HostInfoRange) GetHostIP() string {
	return hir.HostIP
}

// GetPortNum returns the port number
func (hir *HostInfoRange) GetPortNum() int {
	return hir.PortNum
}

// GetStartTime returns the start time
func (hir *HostInfoRange) GetStartTime() string {
	return hir.StartTime
}

// GetEndTime returns the end time
func (hir *HostInfoRange) GetEndTime() string {
	return hir.EndTime
}

// GetLimit returns the limit
func (hir *HostInfoRange) GetLimit() int {
	return hir.Limit
}

// GetOffset returns the offset
func (hir *HostInfoRange) GetOffset() int {
	return hir.Offset
}

// GetLoginName returns the login name
func (hir *HostInfoRange) GetLoginName() string {
	return hir.LoginName
}

// GetConfig gets the configuration
func (hir *HostInfoRange) GetConfig() (depquery.Config, error) {
	return getConfig(hir.GetStartTime(), hir.GetEndTime(), hir.GetLimit(), hir.GetOffset(), hir.GetLoginName())
}

type MySQLServerAndMonitorSystemInfoRange struct {
	Token                    string `json:"token" binding:"required"`
	MySQLServerHostIP        string `json:"mysql_server_host_ip" bind:"required"`
	MySQLServerPortNum       int    `json:"mysql_server_port_num" bind:"required"`
	MySQLServerServiceName   string `json:"mysql_server_service_name" binding:"required"`
	MonitorSystemSystemType  int    `json:"monitor_system_system_type" binding:"required"`
	MonitorSystemHostIP      string `json:"monitor_system_host_ip" binding:"required"`
	MonitorSystemPortNumSlow int    `json:"monitor_system_port_num_slow" binding:"required"`
	StartTime                string `json:"start_time" bind:"required"`
	EndTime                  string `json:"end_time" bind:"required"`
	Limit                    int    `json:"limit" bind:"required"`
	Offset                   int    `json:"offset" bind:"required"`
	LoginName                string `json:"login_name" bind:"required"`
}

// GetToken returns the token
func (ir *MySQLServerAndMonitorSystemInfoRange) GetToken() string {
	return ir.Token
}

// GetMySQLServerHostIP returns the mysql server host ip
func (ir *MySQLServerAndMonitorSystemInfoRange) GetMySQLServerHostIP() string {
	return ir.MySQLServerHostIP
}

// GetMySQLServerPortNum returns the mysql server port number
func (ir *MySQLServerAndMonitorSystemInfoRange) GetMySQLServerPortNum() int {
	return ir.MySQLServerPortNum
}

// GetMySQLServerServiceName returns the mysql server service name
func (ir *MySQLServerAndMonitorSystemInfoRange) GetMySQLServerServiceName() string {
	return ir.MySQLServerServiceName
}

// GetMonitorSystemSystemType returns the monitor system system type
func (ir *MySQLServerAndMonitorSystemInfoRange) GetMonitorSystemSystemType() int {
	return ir.MonitorSystemSystemType
}

// GetMonitorSystemHostIP returns the monitor system host ip
func (ir *MySQLServerAndMonitorSystemInfoRange) GetMonitorSystemHostIP() string {
	return ir.MonitorSystemHostIP
}

// GetMonitorSystemPortNumSlow returns the monitor system port number slow
func (ir *MySQLServerAndMonitorSystemInfoRange) GetMonitorSystemPortNumSlow() int {
	return ir.MonitorSystemPortNumSlow
}

// GetStartTime returns the start time
func (ir *MySQLServerAndMonitorSystemInfoRange) GetStartTime() string {
	return ir.StartTime
}

// GetEndTime returns the end time
func (ir *MySQLServerAndMonitorSystemInfoRange) GetEndTime() string {
	return ir.EndTime
}

// GetLimit returns the limit
func (ir *MySQLServerAndMonitorSystemInfoRange) GetLimit() int {
	return ir.Limit
}

// GetOffset returns the offset
func (ir *MySQLServerAndMonitorSystemInfoRange) GetOffset() int {
	return ir.Offset
}

// GetLoginName returns the login name
func (ir *MySQLServerAndMonitorSystemInfoRange) GetLoginName() string {
	return ir.LoginName
}

// GetConfig gets the configuration
func (ir *MySQLServerAndMonitorSystemInfoRange) GetConfig() (depquery.Config, error) {
	return getConfig(ir.GetStartTime(), ir.GetEndTime(), ir.GetLimit(), ir.GetOffset(), ir.GetLoginName())
}

type DBRange struct {
	Token     string `json:"token" binding:"required"`
	DBID      int    `json:"db_id" bind:"required"`
	StartTime string `json:"start_time" bind:"required"`
	EndTime   string `json:"end_time" bind:"required"`
	Limit     int    `json:"limit" bind:"required"`
	Offset    int    `json:"offset" bind:"required"`
	LoginName string `json:"login_name" bind:"required"`
}

// GetToken returns the token
func (dr *DBRange) GetToken() string {
	return dr.Token
}

// GetDBID returns the db id
func (dr *DBRange) GetDBID() int {
	return dr.DBID
}

// GetStartTime returns the start time
func (dr *DBRange) GetStartTime() string {
	return dr.StartTime
}

// GetEndTime returns the end time
func (dr *DBRange) GetEndTime() string {
	return dr.EndTime
}

// GetLimit returns the limit
func (dr *DBRange) GetLimit() int {
	return dr.Limit
}

// GetOffset returns the offset
func (dr *DBRange) GetOffset() int {
	return dr.Offset
}

// GetLoginName returns the login name
func (dr *DBRange) GetLoginName() string {
	return dr.LoginName
}

// GetConfig gets the configuration
func (dr *DBRange) GetConfig() (depquery.Config, error) {
	return getConfig(dr.GetStartTime(), dr.GetEndTime(), dr.GetLimit(), dr.GetOffset(), dr.GetLoginName())
}

type DBNameAndMySQLServerAndMonitorSystemInfoRange struct {
	Token                    string `json:"token" binding:"required"`
	DBName                   string `json:"db_name" binding:"required"`
	MySQLServerHostIP        string `json:"mysql_server_host_ip" bind:"required"`
	MySQLServerPortNum       int    `json:"mysql_server_port_num" bind:"required"`
	MySQLServerServiceName   string `json:"mysql_server_service_name" binding:"required"`
	MonitorSystemSystemType  int    `json:"monitor_system_system_type" binding:"required"`
	MonitorSystemHostIP      string `json:"monitor_system_host_ip" binding:"required"`
	MonitorSystemPortNumSlow int    `json:"monitor_system_port_num_slow" binding:"required"`
	StartTime                string `json:"start_time" bind:"required"`
	EndTime                  string `json:"end_time" bind:"required"`
	Limit                    int    `json:"limit" bind:"required"`
	Offset                   int    `json:"offset" bind:"required"`
	LoginName                string `json:"login_name" bind:"required"`
}

// GetToken returns the token
func (ir *DBNameAndMySQLServerAndMonitorSystemInfoRange) GetToken() string {
	return ir.Token
}

// GetDBName returns the db name
func (ir *DBNameAndMySQLServerAndMonitorSystemInfoRange) GetDBName() string {
	return ir.DBName
}

// GetMySQLServerHostIP returns the mysql server host ip
func (ir *DBNameAndMySQLServerAndMonitorSystemInfoRange) GetMySQLServerHostIP() string {
	return ir.MySQLServerHostIP
}

// GetMySQLServerPortNum returns the mysql server port number
func (ir *DBNameAndMySQLServerAndMonitorSystemInfoRange) GetMySQLServerPortNum() int {
	return ir.MySQLServerPortNum
}

// GetMySQLServerServiceName returns the mysql server service name
func (ir *DBNameAndMySQLServerAndMonitorSystemInfoRange) GetMySQLServerServiceName() string {
	return ir.MySQLServerServiceName
}

// GetMonitorSystemSystemType returns the monitor system system type
func (ir *DBNameAndMySQLServerAndMonitorSystemInfoRange) GetMonitorSystemSystemType() int {
	return ir.MonitorSystemSystemType
}

// GetMonitorSystemHostIP returns the monitor system host ip
func (ir *DBNameAndMySQLServerAndMonitorSystemInfoRange) GetMonitorSystemHostIP() string {
	return ir.MonitorSystemHostIP
}

// GetMonitorSystemPortNumSlow returns the monitor system port number slow
func (ir *DBNameAndMySQLServerAndMonitorSystemInfoRange) GetMonitorSystemPortNumSlow() int {
	return ir.MonitorSystemPortNumSlow
}

// GetStartTime returns the start time
func (ir *DBNameAndMySQLServerAndMonitorSystemInfoRange) GetStartTime() string {
	return ir.StartTime
}

// GetEndTime returns the end time
func (ir *DBNameAndMySQLServerAndMonitorSystemInfoRange) GetEndTime() string {
	return ir.EndTime
}

// GetLimit returns the limit
func (ir *DBNameAndMySQLServerAndMonitorSystemInfoRange) GetLimit() int {
	return ir.Limit
}

// GetOffset returns the offset
func (ir *DBNameAndMySQLServerAndMonitorSystemInfoRange) GetOffset() int {
	return ir.Offset
}

// GetLoginName returns the login name
func (ir *DBNameAndMySQLServerAndMonitorSystemInfoRange) GetLoginName() string {
	return ir.LoginName
}

// GetConfig gets the configuration
func (ir *DBNameAndMySQLServerAndMonitorSystemInfoRange) GetConfig() (depquery.Config, error) {
	return getConfig(ir.GetStartTime(), ir.GetEndTime(), ir.GetLimit(), ir.GetOffset(), ir.GetLoginName())
}

type SQLIDRange struct {
	Token         string `json:"token" binding:"required"`
	MySQLServerID int    `json:"mysql_server_id" bind:"required"`
	SQLID         string `json:"sql_id" bind:"required"`
	StartTime     string `json:"start_time" bind:"required"`
	EndTime       string `json:"end_time" bind:"required"`
	LoginName     string `json:"login_name" bind:"required"`
}

// GetToken returns the token
func (sir *SQLIDRange) GetToken() string {
	return sir.Token
}

// GetMySQLServerID returns the mysql server id
func (sir *SQLIDRange) GetMySQLServerID() int {
	return sir.MySQLServerID
}

// GetSQLID returns the sql id
func (sir *SQLIDRange) GetSQLID() string {
	return sir.SQLID
}

// GetStartTime returns the start time
func (sir *SQLIDRange) GetStartTime() string {
	return sir.StartTime
}

// GetEndTime returns the end time
func (sir *SQLIDRange) GetEndTime() string {
	return sir.EndTime
}

// GetLoginName returns the login name
func (sir *SQLIDRange) GetLoginName() string {
	return sir.LoginName
}

// GetConfig gets the configuration
func (sir *SQLIDRange) GetConfig() (depquery.Config, error) {
	return getConfig(sir.GetStartTime(), sir.GetEndTime(), constant.ZeroInt, constant.ZeroInt, sir.GetLoginName())
}

// getConfig gets the configuration
func getConfig(startTime, endTime string, limit, offset int, loginName string) (depquery.Config, error) {
	st, err := time.ParseInLocation(constant.TimeLayoutSecond, startTime, time.Local)
	if err != nil {
		return nil, errors.Trace(err)
	}
	et, err := time.ParseInLocation(constant.TimeLayoutSecond, endTime, time.Local)
	if err != nil {
		return nil, errors.Trace(err)
	}

	return NewConfig(st, et, limit, offset, loginName), nil
}

type SQLIDAndMySQLServerAndMonitorSystemInfoRange struct {
	Token                    string `json:"token" binding:"required"`
	SQLID                    string `json:"sql_id" binding:"required"`
	MySQLServerHostIP        string `json:"mysql_server_host_ip" bind:"required"`
	MySQLServerPortNum       int    `json:"mysql_server_port_num" bind:"required"`
	MySQLServerServiceName   string `json:"mysql_server_service_name" binding:"required"`
	MonitorSystemSystemType  int    `json:"monitor_system_system_type" binding:"required"`
	MonitorSystemHostIP      string `json:"monitor_system_host_ip" binding:"required"`
	MonitorSystemPortNumSlow int    `json:"monitor_system_port_num_slow" binding:"required"`
	StartTime                string `json:"start_time" bind:"required"`
	EndTime                  string `json:"end_time" bind:"required"`
	Limit                    int    `json:"limit" bind:"required"`
	Offset                   int    `json:"offset" bind:"required"`
	LoginName                string `json:"login_name" bind:"required"`
}

// GetToken returns the token
func (ir *SQLIDAndMySQLServerAndMonitorSystemInfoRange) GetToken() string {
	return ir.Token
}

// GetSQLID returns the sql id
func (ir *SQLIDAndMySQLServerAndMonitorSystemInfoRange) GetSQLID() string {
	return ir.SQLID
}

// GetMySQLServerHostIP returns the mysql server host ip
func (ir *SQLIDAndMySQLServerAndMonitorSystemInfoRange) GetMySQLServerHostIP() string {
	return ir.MySQLServerHostIP
}

// GetMySQLServerPortNum returns the mysql server port number
func (ir *SQLIDAndMySQLServerAndMonitorSystemInfoRange) GetMySQLServerPortNum() int {
	return ir.MySQLServerPortNum
}

// GetMySQLServerServiceName returns the mysql server service name
func (ir *SQLIDAndMySQLServerAndMonitorSystemInfoRange) GetMySQLServerServiceName() string {
	return ir.MySQLServerServiceName
}

// GetMonitorSystemSystemType returns the monitor system system type
func (ir *SQLIDAndMySQLServerAndMonitorSystemInfoRange) GetMonitorSystemSystemType() int {
	return ir.MonitorSystemSystemType
}

// GetMonitorSystemHostIP returns the monitor system host ip
func (ir *SQLIDAndMySQLServerAndMonitorSystemInfoRange) GetMonitorSystemHostIP() string {
	return ir.MonitorSystemHostIP
}

// GetMonitorSystemPortNumSlow returns the monitor system port number slow
func (ir *SQLIDAndMySQLServerAndMonitorSystemInfoRange) GetMonitorSystemPortNumSlow() int {
	return ir.MonitorSystemPortNumSlow
}

// GetStartTime returns the start time
func (ir *SQLIDAndMySQLServerAndMonitorSystemInfoRange) GetStartTime() string {
	return ir.StartTime
}

// GetEndTime returns the end time
func (ir *SQLIDAndMySQLServerAndMonitorSystemInfoRange) GetEndTime() string {
	return ir.EndTime
}

// GetLimit returns the limit
func (ir *SQLIDAndMySQLServerAndMonitorSystemInfoRange) GetLimit() int {
	return ir.Limit
}

// GetOffset returns the offset
func (ir *SQLIDAndMySQLServerAndMonitorSystemInfoRange) GetOffset() int {
	return ir.Offset
}

// GetLoginName returns the login name
func (ir *SQLIDAndMySQLServerAndMonitorSystemInfoRange) GetLoginName() string {
	return ir.LoginName
}

// GetConfig gets the configuration
func (ir *SQLIDAndMySQLServerAndMonitorSystemInfoRange) GetConfig() (depquery.Config, error) {
	return getConfig(ir.GetStartTime(), ir.GetEndTime(), ir.GetLimit(), ir.GetOffset(), ir.GetLoginName())
}

// GetDBName gets the db name from the given sql
func GetDBName(sql string) (string, error) {
	p := parser.NewParserWithDefault()
	r, err := p.Parse(sql)
	if err != nil {
		return constant.EmptyString, err
	}

	if len(r.GetDBNames()) > constant.ZeroInt {
		return r.GetDBNames()[constant.ZeroInt], nil
	}

	return constant.EmptyString, nil
}

// GetTableName gets the table names from the given sql
func GetTableNames(sql string) ([]string, error) {
	p := parser.NewParserWithDefault()
	r, err := p.Parse(sql)
	if err != nil {
		return nil, err
	}

	return r.GetTableNames(), nil
}
